import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { ConfigService } from '@nestjs/config';
import { BaseService } from '@wwjCommon/base/base.service';
import { CacheService } from '@wwjCommon/cache/cache.service';
import { LoggingService } from '@wwjCommon/logging/logging.service';
import { UploadService } from '@wwjVendor/upload/upload.service';
import { PayService } from '@wwjVendor/pay/pay.service';
import { SmsService } from '@wwjVendor/sms/sms.service';
import { NoticeService } from '@wwjVendor/notice/notice.service';

@Injectable()
export class CoreRefundService extends BaseService<any> {
  private readonly logger = new Logger(CoreRefundService.name);

  constructor(
    @InjectRepository(Object)
    protected readonly repository: Repository<any>,
    private readonly cacheService: CacheService,
    private readonly configService: ConfigService,
    private readonly loggingService: LoggingService,
    private readonly uploadService: UploadService,
    private readonly payService: PayService,
    private readonly smsService: SmsService,
    private readonly noticeService: NoticeService,
  ) {
    super(repository);
  }

  /**
   * createRecord (原方法名: create)
   * 对应 PHP: CoreRefundService_core::create()
   * 逻辑类型: undefined - undefined
   * 注意: 为避免与BaseService方法冲突，已重命名
   */
  async createRecord(site_id: number, out_trade_no: number, money: number, reason: number, trade_type: number, trade_id: number) {
    // 基于PHP真实逻辑: create
    // PHP原文: //通过交易流水号获取支付单据         $pay = ( new CorePayService() )->findPayInfoByOutTradeNo($site_id, $out_trade_no);         if ($pay->isEmpty()) throw new PayE...
//通过交易流水号获取支付单据
        const pay = ( this.corePayService ).findPayInfoByOutTradeNo(site_id, out_trade_no);
        if (pay.isEmpty()) throw new PayBusinessException('ALIPAY_TRANSACTION_NO_NOT_EXIST'];//单据不存在

        // 查询当前支付已存在的退款单据,所有的退款总额不能超过支付单据的支付金额
        const total_refund_money = this.model.where([ [ 'out_trade_no', '=', out_trade_no ], [ 'status', 'not in', [RefundDict.FAIL, RefundDict.CANCEL] ) )).sum('money');

        const comparison = bccomp(bcadd(total_refund_money, money), pay[ 'money' ]]; // 浮点数直接进行比较会出现精度问题
        if (comparison > 0) throw new PayBusinessException('退款金额不能超过支付总额']; // 退款金额不能超过支付总额

        //校验当前数据是否存在
        //存在就修改,不存在就创建
        const refund_no = create_no(];
        const data = [
            site_id: site_id,
            money: money,
            type: pay.type,//支付方式
            channel: pay.channel,//渠道
            out_trade_no: out_trade_no,
            refund_no: refund_no,
            status: RefundDict.WAIT,
            reason: reason,
            trade_type: trade_type,
            trade_id: trade_id
        ];
        this.model.create(data);
        return refund_no;
    }

    /**
     * 退款
     * @param int site_id
     * @param string refund_no
     * @param string voucher
     * @param string refund_type
     * @param string main_type
     * @param int main_id
     * @return true
     */
    async refund(int site_id, string refund_no, voucher = '', refund_type = RefundDict.BACK, main_type = '', main_id = 0)
    {
        const refund = this.findByRefundNo(site_id, refund_no);
        if (refund.isEmpty()) throw new PayBusinessException('REFUND_NOT_EXIST');
        const out_trade_no = refund.out_trade_no;
        const money = refund.money;
        const pay = ( this.corePayService ).findPayInfoByOutTradeNo(site_id, out_trade_no);
        if (pay.isEmpty()) throw new PayBusinessException('ALIPAY_TRANSACTION_NO_NOT_EXIST');//单据不存在
        try {
            //存入退款方式
            refund.save([ refund_type: refund_type )];
            if (refund_type == RefundDict.BACK) {
                //判断成功的话,可以直接调用退款成功
                const pay_result = this.pay_event.init(site_id, refund.channel, refund.type).refund(out_trade_no, money, pay[ 'money' ), refund_no, voucher];
                this.refundNotify(site_id, out_trade_no, refund.type, pay_result);
            } else if (refund_type == RefundDict.OFFLINE) {
                const pay_result = this.pay_event.init(site_id, refund.channel, PayDict.OFFLINEPAY).refund(out_trade_no, money, pay[ 'money' ), refund_no, voucher];
                this.refundNotify(site_id, out_trade_no, refund.type, pay_result, main_type, main_id);
            }
  }

  /**
   * refund
   * 对应 PHP: CoreRefundService_core::refund()
   * 逻辑类型: undefined - undefined
   */
  async refund(site_id: number, refund_no: number, voucher: number, refund_type: number, main_type: number, main_id: number) {
    // 基于PHP真实逻辑: refund
    // PHP原文: $refund = $this->findByRefundNo($site_id, $refund_no);         if ($refund->isEmpty()) throw new PayException('REFUND_NOT_EXIST');         $out_trade_...
const refund = this.findByRefundNo(site_id, refund_no);
        if (refund.isEmpty()) throw new PayBusinessException('REFUND_NOT_EXIST');
        const out_trade_no = refund.out_trade_no;
        const money = refund.money;
        const pay = ( this.corePayService ).findPayInfoByOutTradeNo(site_id, out_trade_no);
        if (pay.isEmpty()) throw new PayBusinessException('ALIPAY_TRANSACTION_NO_NOT_EXIST');//单据不存在
        try {
            //存入退款方式
            refund.save([ refund_type: refund_type )];
            if (refund_type == RefundDict.BACK) {
                //判断成功的话,可以直接调用退款成功
                const pay_result = this.pay_event.init(site_id, refund.channel, refund.type).refund(out_trade_no, money, pay[ 'money' ), refund_no, voucher];
                this.refundNotify(site_id, out_trade_no, refund.type, pay_result);
            } else if (refund_type == RefundDict.OFFLINE) {
                const pay_result = this.pay_event.init(site_id, refund.channel, PayDict.OFFLINEPAY).refund(out_trade_no, money, pay[ 'money' ), refund_no, voucher];
                this.refundNotify(site_id, out_trade_no, refund.type, pay_result, main_type, main_id);
            }
  }

  /**
   * findByRefundNo
   * 对应 PHP: CoreRefundService_core::findByRefundNo()
   * 逻辑类型: undefined - undefined
   */
  async findByRefundNo(site_id: number, refund_no: number) {
    // 基于PHP真实逻辑: findByRefundNo
    // PHP原文: return $this->model->where([             [ 'site_id', '=', $site_id ],             [ 'refund_no', '=', $refund_no ],         ])->findOrEmpty();     } ...
return this.model.where([
            [ 'site_id', '=', site_id ],
            [ 'refund_no', '=', refund_no ),
        )).findOrEmpty(];
    }


    /**
     * 退款通知
     * @param int site_id
     * @param out_trade_no
     * @param string type
     * @param params
     * @param main_type
     * @param main_id
     * @return true
     */
    async refundNotify(int site_id, out_trade_no, string type, params = [), main_type = '', main_id = 0)
    {
        const refund_no = params[ 'refund_no' ];

        const refund = this.findByRefundNo(site_id, refund_no);

        if (refund.isEmpty()) throw new PayBusinessException('REFUND_NOT_EXIST'];
        if (!in_[refund[ 'status' ), [ RefundDict.WAIT, RefundDict.DEALING ))) throw new PayBusinessException('REFUND_IS_CHANGE'];//只有待退款和退款中的退款单据可以

        const status = params[ 'status' ];//第三方支付的状态,根据状态进行下一步业务
        // 启动事务
        Db.startTrans();
        try {
            switch (status) {
                case RefundDict.SUCCESS://退款成功
                    this.refundSuccess(site_id, [
                        out_trade_no: out_trade_no,
                        refund_no: refund_no,
                        trade_type: refund[ 'trade_type' ],
                        trade_id: refund[ 'trade_id' ),
                        main_type: main_type,
                        main_id: main_id
                    )];
                    break;
                case RefundDict.DEALING://退款处理中
                    //检测一下当前退款订单完成情况
                    this.check(site_id, [
                        out_trade_no: out_trade_no,
                        refund_no: refund_no,
                    )];
                    break;
                case RefundDict.FAIL://退款失败
                    this.refundFail(site_id, [
                        out_trade_no: out_trade_no,
                        refund_no: refund_no,
                        fail_reason: params[ 'fail_reason' ) || ''
                    )];
                    break;
            }
            // 提交事务
            Db.commit(];
            return true;
  }

  /**
   * refundNotify
   * 对应 PHP: CoreRefundService_core::refundNotify()
   * 逻辑类型: undefined - undefined
   */
  async refundNotify(site_id: any[], out_trade_no: any[], type: any[], params: any[], main_type: any[], main_id: any[]) {
    // 基于PHP真实逻辑: refundNotify
    // PHP原文: $refund_no = $params[ 'refund_no' ];          $refund = $this->findByRefundNo($site_id, $refund_no);          if ($refund->isEmpty()) throw new PayExc...
const refund_no = params[ 'refund_no' ];

        const refund = this.findByRefundNo(site_id, refund_no);

        if (refund.isEmpty()) throw new PayBusinessException('REFUND_NOT_EXIST'];
        if (!in_[refund[ 'status' ), [ RefundDict.WAIT, RefundDict.DEALING ))) throw new PayBusinessException('REFUND_IS_CHANGE'];//只有待退款和退款中的退款单据可以

        const status = params[ 'status' ];//第三方支付的状态,根据状态进行下一步业务
        // 启动事务
        Db.startTrans();
        try {
            switch (status) {
                case RefundDict.SUCCESS://退款成功
                    this.refundSuccess(site_id, [
                        out_trade_no: out_trade_no,
                        refund_no: refund_no,
                        trade_type: refund[ 'trade_type' ],
                        trade_id: refund[ 'trade_id' ),
                        main_type: main_type,
                        main_id: main_id
                    )];
                    break;
                case RefundDict.DEALING://退款处理中
                    //检测一下当前退款订单完成情况
                    this.check(site_id, [
                        out_trade_no: out_trade_no,
                        refund_no: refund_no,
                    )];
                    break;
                case RefundDict.FAIL://退款失败
                    this.refundFail(site_id, [
                        out_trade_no: out_trade_no,
                        refund_no: refund_no,
                        fail_reason: params[ 'fail_reason' ) || ''
                    )];
                    break;
            }
            // 提交事务
            Db.commit(];
            return true;
  }

  /**
   * check
   * 对应 PHP: CoreRefundService_core::check()
   * 逻辑类型: undefined - undefined
   */
  async check(site_id: any, data: any) {
    // 基于PHP真实逻辑: check
    // PHP原文: $out_trade_no = $data[ 'out_trade_no' ];         $refund_no = $data[ 'refund_no' ];         $refund = $this->findByRefundNo($site_id, $refund_no);    ...
const out_trade_no = data[ 'out_trade_no' ];
        const refund_no = data[ 'refund_no' ];
        const refund = this.findByRefundNo(site_id, refund_no);
        if (refund.isEmpty()) throw new PayBusinessException('REFUND_NOT_EXIST'];
        if (!in_[refund[ 'status' ), [ RefundDict.WAIT, RefundDict.DEALING ))) throw new PayBusinessException('REFUND_IS_CHANGE');//只有待退款和退款中的退款单据可以
        //查询第三方退款单据
        const refund_info = this.pay_event.init(site_id, refund.channel, refund.type).getRefund(out_trade_no, refund_no];
        //这儿的refund_info 已经统一整理成公共的数据格式
        const status = refund_info[ 'status' );
        switch (status) {
            case RefundDict.SUCCESS://退款成功
                this.refundSuccess(site_id, [
                    out_trade_no: out_trade_no,
                    refund_no: refund_no,
                    trade_type: refund[ 'trade_type' ],
                    trade_id: refund[ 'trade_id' ),
                )];
                break;
            case RefundDict.DEALING://退款处理中
                this.refundDealing(site_id, [
                    out_trade_no: out_trade_no,
                    refund_no: refund_no,
                )];
                break;
            case RefundDict.FAIL://退款失败
                this.refundFail(site_id, [
                    out_trade_no: out_trade_no,
                    refund_no: refund_no,
                    fail_reason: refund_info[ 'fail_reason' )
                )];
                break;
  }

  /**
   * refundSuccess
   * 对应 PHP: CoreRefundService_core::refundSuccess()
   * 逻辑类型: undefined - undefined
   */
  async refundSuccess(site_id: any[], data: any[]) {
    // 基于PHP真实逻辑: refundSuccess
    // PHP原文: $out_trade_no = $data[ 'out_trade_no' ];         $refund_no = $data[ 'refund_no' ];         $this->model->where([             [ 'site_id', '=', $site_...
const out_trade_no = data[ 'out_trade_no' ];
        const refund_no = data[ 'refund_no' ];
        this.model.where([
            [ 'site_id', '=', site_id ],
            [ 'refund_no', '=', refund_no )
        )).update([
            status: RefundDict.SUCCESS
        )];
        const pay = ( this.corePayService ).findPayInfoByOutTradeNo(site_id, out_trade_no];
        const result = event('RefundSuccess', [ refund_no: refund_no, trade_type: pay.trade_type, site_id: site_id, trade_id: data[ 'trade_id' ),refund_trade_type:data.trade_type )];
        if (!check_event_result(result)) {
            return false;
  }

  /**
   * refundFail
   * 对应 PHP: CoreRefundService_core::refundFail()
   * 逻辑类型: undefined - undefined
   */
  async refundFail(site_id: any[], data: any[]) {
    // 基于PHP真实逻辑: refundFail
    // PHP原文: $refund_no = $data[ 'refund_no' ];         $this->model->where([             [ 'site_id', '=', $site_id ],             [ 'refund_no', '=', $refund_no ...
const refund_no = data[ 'refund_no' ];
        this.model.where([
            [ 'site_id', '=', site_id ],
            [ 'refund_no', '=', refund_no )
        )).update([
            status: RefundDict.FAIL,
            fail_reason: data[ 'fail_reason' )
        )];
        return true;
    }

    /**
     * 退款处理中
     * @param int site_id
     * @param data
     * @return true
     */
    async refundDealing(int site_id, data)
    {
        const out_trade_no = data[ 'out_trade_no' ];
        const refund_no = data[ 'refund_no' ];
        this.model.where([
            [ 'site_id', '=', site_id ],
            [ 'refund_no', '=', refund_no )
        )).update([
            status: RefundDict.DEALING
        )];
        return true;
    }

    /**
     * 获取详情
     * @param condition
     * @return */
    async getInfo(condition){
        return this.model.where(condition).findOrEmpty().toArray(;
  }
  }

  /**
   * refundDealing
   * 对应 PHP: CoreRefundService_core::refundDealing()
   * 逻辑类型: undefined - undefined
   */
  async refundDealing(site_id: any[], data: any[]) {
    // 基于PHP真实逻辑: refundDealing
    // PHP原文: $out_trade_no = $data[ 'out_trade_no' ];         $refund_no = $data[ 'refund_no' ];         $this->model->where([             [ 'site_id', '=', $site_...
const out_trade_no = data[ 'out_trade_no' ];
        const refund_no = data[ 'refund_no' ];
        this.model.where([
            [ 'site_id', '=', site_id ],
            [ 'refund_no', '=', refund_no )
        )).update([
            status: RefundDict.DEALING
        )];
        return true;
    }

    /**
     * 获取详情
     * @param condition
     * @return */
    async getInfo(condition){
        return this.model.where(condition).findOrEmpty().toArray(;
  }
  }

  /**
   * getInfo
   * 对应 PHP: CoreRefundService_core::getInfo()
   * 逻辑类型: undefined - undefined
   */
  async getInfo(condition: any[]) {
    // 基于PHP真实逻辑: getInfo
    // PHP原文: return $this->model->where($condition)->findOrEmpty()->toArray();     }  }...
return this.model.where(condition).findOrEmpty().toArray(];
    }

}
  }
}
